package motodev.app;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;
import javax.crypto.spec.SecretKeySpec;

import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Random;

public class Cryptography {

	/**
	 * Creates values that are used for diffie hellman encryption.
	 * @return Array of the keys generated.
	 */
	public static int[] BeginKeyExchange()
	{
		Random generator = new Random();
		int[] keys = new int[2];
		int p = 17;
		int g = generator.nextInt(p-2) + 1;
		
		keys[0] = p;
		keys[1] = Math.abs(g);
		
		return keys;
	}

	/**
	 * Picks each users secret number
	 * @return returns the secret number generated
	 */
	public static int PickNumber()
	{
		Random generator = new Random();
		
		int result = Math.abs(generator.nextInt(5) + 1);
		return result;
		
	}

	/**
	 * Calculates the users Y value based on G, X and P
	 * @param P Prime number
	 * @param G Generator
	 * @param X Secret number
	 * @return The calculated Y value.
	 */
	public static int GenerateY(int P, int G, int X)
	{
		int newG = G;
		for (int i = 1; i < X; i++)
		{
			newG *= G;
		}
		
		return newG % P;
	}

	/**
	 * Calculates the users secret value based on Y, X and P
	 * @param P Prime number
	 * @param Y Users Y value
	 * @param X Secret number
	 * @return The calculated secret value.
	 */
	public static int GenerateSecretKey(int Y, int X, int P)
	{
		int newY = Y;
		for (int i = 1; i < X; i++)
		{
			newY *= Y;
		}
		
		return newY % P;
	}

	/**
	 * Encrypts players move.
	 * @param col Column that a player has entered 
	 * @param sKey Symmetric Key
	 * @return Encrypted move as a string
	 */
	public static String Encrypt(int col, int sKey)
	{	
		byte[] keyBytes = Integer.toString(sKey).getBytes();
		SecretKeySpec key = new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES");
		byte[] input = new String("m" + col).getBytes();
		Cipher cipher;
		
		try {
			cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
			cipher.init(Cipher.ENCRYPT_MODE, key);

		    byte[] cipherText = new byte[500];
		    int ctLength = 0;

			ctLength = cipher.update(input, 0, input.length, cipherText, 0);

		    ctLength += cipher.doFinal(input, 0, ctLength, cipherText, 0);

		    return cipherText.toString();
		    
		} catch (NoSuchAlgorithmException e1) {
			e1.printStackTrace();
		} catch (NoSuchPaddingException e1) {
			e1.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (ShortBufferException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		
		return "";
	}

	/**
	 * Decrypts a players move.
	 * @param cipherText The byte array representing the cypher text.
	 * @param keyBytes Array of bytes with decrypted message.
	 * @return The column where the move is placed.
	 */
	public static int Decrypt(byte[] cipherText, byte[] keyBytes)
	{
		SecretKeySpec key = new SecretKeySpec(keyBytes, 0, keyBytes.length, "AES");
		
	    Cipher cipher;
		try {
			cipher = Cipher.getInstance("AES/ECB/PKCS7Padding");
			
			int ctLength = cipherText.length;
		    cipher.init(Cipher.DECRYPT_MODE, key);
		    
		    byte[] plainText = new byte[500];
		    int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);
		    ptLength += cipher.doFinal(plainText, 0, ptLength, cipherText, 0);

			
			return plainText[13];
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
		} catch (InvalidKeyException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (ShortBufferException e) {
			e.printStackTrace();
		} catch (IllegalBlockSizeException e) {
			e.printStackTrace();
		} catch (BadPaddingException e) {
			e.printStackTrace();
		}
		
		return 'a';
	}
}
